package system.service;

import com.jfinal.aop.Before;
import com.jfinal.aop.Duang;
import com.jfinal.aop.Enhancer;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.sun.org.apache.regexp.internal.RE;
import core.exception.AccountingException;
import core.shiro.ShiroUtils;
import core.toolbox.Int.IntUtils;
import core.toolbox.Period.PeriodUtils;
import system.dao.SubjectBalanceDao;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Administrator on 2017/3/16.
 */
public class UserSubjectBalanceService {

    SubjectBalanceDao subjectBalanceDao = Duang.duang(SubjectBalanceDao.class);
    VoucherService voucherService = Enhancer.enhance(VoucherService.class);



    public void insert(Record record){
        /////获取当前登录的用户id
        int uid = ShiroUtils.getUserId();
        /////获取当前周期
        int period = PeriodUtils.getCurrentPeriod();
        /////获取凭证详细信息
        List<Record> detail = record.get("voucher_detail");
        //记录到余额数据
        for(Record r : detail){
            r.set("user_id", uid).set("account_period", period).remove("voucher_digest");
            subjectBalanceDao.sureBalanceSubject(r);
            //发生余额数据
            subjectBalanceDao.updateDetailForOccurredBalance(r);
            //累计余额数据
            subjectBalanceDao.updateDetailForAccumulatedBalance(r);
        }


    }


    /**
     * 根据凭证编号删除余额记录
     * @param voucher_id
     * @return
     */
    @Before(Tx.class)
    public void deleteUserBalanceRecordByVoucherId(int ...voucher_id) {
        ////去除重复凭证编号
        Integer[] ids = IntUtils.removeDuplicates(voucher_id);
        /////获取当前登录的用户id
        int uid = ShiroUtils.getUserId();
        /////获取当前周期
        int period = PeriodUtils.getCurrentPeriod();

        for (int id : ids) {
            Record voucherInfo = voucherService.getVoucherInfoById(id);
            List<Record> details = voucherInfo.get("detail");
            for(Record detail : details) {
                detail.set("user_id", uid).set("account_period", period);
                boolean b = subjectBalanceDao.removeDetailForBalance(detail);
                if (!b)
                    throw new AccountingException("删除凭证失败");
            }
        }



    }

    /**
     * 获取会计期间里的用户会计余额记录
     * @param start 开始周期
     * @param end 结束周期
     * @return
     */
    public List getSubjectBalanceDuringPeriod(int start, int end){
        int user_id = ShiroUtils.getUserId();
        //期初余额
        List<Record> startAccumulatedBalance = subjectBalanceDao.getUserSubjectAccumulatedBalanceByPeriod(user_id, start);
        //期末余额
        List<Record> endAccumulatedBalance = subjectBalanceDao.getUserSubjectAccumulatedBalanceByPeriod(user_id, end + 1);
        //发生余额
        List<Record> occurredBalance = null;
        if(start == end)
            occurredBalance = subjectBalanceDao.getUserSubjectOccurredBalanceByPeriod(user_id, start);
        else if (start < end) {
            occurredBalance = getUserSubjectOccurredBalanceByAccumulatedBalance(startAccumulatedBalance, endAccumulatedBalance);
        } else {
            throw new AccountingException("开始会计周期["+start+"]大于结束会计周期["+end+"]");
        }
        List subjectBalance = mergeBalance(startAccumulatedBalance, endAccumulatedBalance, occurredBalance);

        return subjectBalance;
    }

    /**
     * 合并余额记录
     * @param startAccumulatedBalance
     * @param endAccumulatedBalance
     * @param occurredBalance
     * @return
     */
    private List mergeBalance(List<Record> startAccumulatedBalance, List<Record> endAccumulatedBalance, List<Record> occurredBalance) {
        List subjectBalance = new LinkedList();
        initSubjectBalanceByEndAccumulatedBalance(endAccumulatedBalance, subjectBalance);
        mergeBalance2SubjectBalance(occurredBalance, subjectBalance, "occurred_");
        mergeBalance2SubjectBalance(startAccumulatedBalance, subjectBalance, "start_");

        return subjectBalance;
    }

    /**
     * 合并余额记录-初始化余额集合
     * @param endAccumulatedBalance
     * @param subjectBalance
     */
    private void initSubjectBalanceByEndAccumulatedBalance(List<Record> endAccumulatedBalance, List subjectBalance) {
        for (Record endData : endAccumulatedBalance) {
            Map map = new LinkedHashMap();
            String subject_id = endData.get("subject_id");
            String subject_name = endData.get("subject_name");
            BigDecimal debit_balance = endData.get("debit_balance");
            BigDecimal credit_balance = endData.get("credit_balance");
            map.put("subject_id", subject_id);
            map.put("subject_name", subject_name);
            map.put("end_debit_balance", debit_balance);
            map.put("end_credit_balance", credit_balance);
            subjectBalance.add(map);
        }
    }

    /**
     * 合并余额记录-合并一个余额记录
     * @param balance
     * @param subjectBalance
     * @param prefix
     */
    private void mergeBalance2SubjectBalance(List<Record> balance, List subjectBalance, String prefix){
        ListIterator listIterator = subjectBalance.listIterator();
        for (Record record : balance) {
            String subject_id = record.get("subject_id");
            String subject_name = record.get("subject_name");
            BigDecimal debit_balance = record.get("debit_balance");
            BigDecimal credit_balance = record.get("credit_balance");
            boolean error = false;
            while (true) {
                if(!listIterator.hasNext()) {
                    if(error) throw new AccountingException("科目余额表数据异常");
                    listIterator = subjectBalance.listIterator();
                    if(!listIterator.hasNext()) return;
                    error = true;
                }
                Map next = (Map) listIterator.next();
                if(next.get("subject_id").equals(subject_id)){
                    next.put(prefix+"debit_balance", debit_balance);
                    next.put(prefix+"credit_balance", credit_balance);
                    break;
                }
            }
        }
    }




    /**
     * 如果开始周期大于结束周期 就通过累计余额记录来计算发生余额
     * @param startPeriod
     * @param endPeriod
     * @return
     */
    private List<Record> getUserSubjectOccurredBalanceByAccumulatedBalance(List<Record> startPeriod, List<Record> endPeriod) {
        List<Record> occurred;
        occurred = new LinkedList();
        a:for(Record endData : endPeriod){
            String subject_id = endData.get("subject_id");
            String subject_name = endData.get("subject_name");
            BigDecimal debit_balance = endData.get("debit_balance");
            BigDecimal credit_balance = endData.get("credit_balance");
            for (Record startData : startPeriod) {
                if(startData.get("subject_id").equals(subject_id)){
                    Record record = new Record();
                    record.set("subject_id", subject_id)
                            .set("subject_name", subject_name)
                            .set("debit_balance", debit_balance.subtract((BigDecimal) startData.get("debit_balance")))
                            .set("credit_balance", credit_balance.subtract((BigDecimal) startData.get("credit_balance")));
                    occurred.add(record);
                    continue a;
                }
            }
            occurred.add(endData);
        }
        return occurred;
    }


}
